package calculator;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Calculator
{
	private Stack			stack;
	// Regulaerer Ausdruck fuer binaere operatorn
	private final String	binaryOperatorsRegExpression	= "max|min";

	private final String	einZeichen	= "/|-|\\+|\\*|\\^";
	// Regulaerer Ausdruck fuer unaere operatorn
	private final String	unaryOperatorsRegExpression		= "sqrt|ceil|floor|sin|cos|abs|log";

	// Regulaerer Ausdruck fuer zahlen
	private final String	numbersRegExpression			= "-?[0-9]+(\\.[0-9]+)?";

	public Calculator()
	{
		this.stack = new Stack();
	}

	public static void main(String[] args) throws IOException
	{
		Calculator calculator = new Calculator();

		// String upn_expr = "26.0 3 1 / +";
		System.out.println("Hi! Ich bin der Rechnikus, wenn ich dir auf den Sack gehe, schreib 'halt maul'!");
		while (true)
		{

			System.out.print("Was soll ich diesmal ausrechnen?  ");
			String upn_expr = calculator.readIn();

			if (upn_expr.equalsIgnoreCase("halt maul"))
			{
				System.out
						.println("Das war schoen! Viel Erfolg in der naechsten Matheklausur! Bye! :)");
				break;
			}

			double erg = calculator.calculate_upn(upn_expr);
			System.out.println("Das war doch simpel.. :) [" + upn_expr + "] = " + erg);
		}

	}

	private boolean isNumber(String word)
	{
		return word.matches(this.numbersRegExpression); // muster fuer zahlen check
	}

	private boolean isBinaryOperator(String word)
	{
		return word.matches(this.binaryOperatorsRegExpression); // muster fuer zahlen check
	}

	private boolean einZeichen(String word)
	{
		return word.matches(this.einZeichen); // muster fuer zahlen check
	}
	
	private boolean isUnaryOperator(String word)
	{
		return word.matches(this.unaryOperatorsRegExpression);
	}

	public double calculate_upn(String upn_expr){
		StringTokenizer tok = new StringTokenizer(upn_expr, " ");
		Calculator calculator = new Calculator();
		
		
		
		
		
		while (tok.hasMoreTokens())
		{
			String nextWord = tok.nextToken();

			if (isNumber(nextWord))
			{
				
				stack.push(Double.parseDouble(nextWord));

			} else if (einZeichen(nextWord))
			{

				Double elem1 = stack.pop();
				Double elem2 = stack.pop();
				double result = 0;

				switch (nextWord.charAt(0)){
				case '+': result = elem1 + elem2;break;
				case '-': result = elem2 - elem1;break;
				case '*': result = elem1 * elem2;break;
				case '/': result = elem2 / elem1;break;
				case '^': result = Math.pow(elem2, elem1);break;
				
				}
				stack.push(result);
			} else if (isBinaryOperator(nextWord))
			{

				Double elem1 = stack.pop();
				Double elem2 = stack.pop();
				double result = 0;

				if (nextWord.equals("max"))
				{
					result = Math.max(elem1,elem2);
				}

				else if (nextWord.equals("min"))
				{
					result = Math.min(elem1, elem2);
				}

				stack.push(result);

			} else if (isUnaryOperator(nextWord))
			{
				Double elem1 = stack.pop();
				
				double result = 0;
				if (nextWord.equals("sqrt"))
				{
					result = Math.sqrt(elem1);

				}
				if (nextWord.equals("ceil"))
				{
					result = Math.ceil(elem1);

				}

				if (nextWord.equals("floor"))
				{
					result = Math.floor(elem1);

				}

				if (nextWord.equals("sin"))
				{
					result = Math.sin(elem1);

				}
				if (nextWord.equals("cos"))
				{
					result = Math.cos(elem1);

				}
				if (nextWord.equals("abs"))
				{
					result = Math.abs(elem1);

				}

				if (nextWord.equals("log"))
				{
					result = Math.log(elem1);

				}

				stack.push(result);
			}
		}
		return stack.pop();
	}

	private String readIn() throws IOException
	{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String read = br.readLine();
		return read;
	}

}